using System;
using System.Collections.Generic;
using System.Text;
using JobShopModel.Model.FactoryLvl;
using JobShopModel.Model.JobLvl;

namespace JobShopModel.Model.Station
{
    /// <summary>
    /// Represent a machine used by stations to perform operations.
    /// Each machine can operation one job at a time.
    /// A station is set Availlable if at least one machine is iddle
    /// States:
    /// <see cref="MachineStates"/>
    /// </summary>
    class Machine
    {
        private MachineStates state;

        private Time blockedTime;
        private Time iddleTime;
        private Time operatingTime;

        private Time sIddleTime;
        private Time sBlockedTime;
        private Time sOperatingTime;

        private Operation currentOperation;

        /// <summary>
        /// State of the Machine
        /// </summary>
        public MachineStates State
        {
            get { return this.state; }
        }

        public Operation CurrentOperation
        {
            get { return this.currentOperation; }
        }


        /// <summary>
        /// Default Constructor
        /// </summary>
        public Machine()
        {
            //Initialize elements
            blockedTime = new Time();
            operatingTime = new Time();
            iddleTime = new Time();

            //Set the machine to Iddle
            this.state = MachineStates.IDDLE;
            this.sIddleTime = new Time(); 
        }

        public Machine(Time startTime)
        {
            //Initialize elements
            blockedTime = new Time();
            operatingTime = new Time();
            iddleTime = new Time();

            //Set the machine to Iddle
            this.state = MachineStates.IDDLE;
            this.sIddleTime = startTime;
        }

        /// <summary>
        /// Called when the job blocking the machine is removed by the transporter
        /// </summary>
        /// <param name="startTime">Time the transport arrived</param>
        /// <returns>Time the machine was Blocked</returns>
        public Time SetIddle(Time startTime)
        {
            Time timeBlocked = startTime - sBlockedTime;

            //Finish the previous state
            if (state == MachineStates.BLOCKED)
            {
                this.blockedTime += timeBlocked;
            }
            else
            {
                throw new Exception("Can not go to IDDLE from current state (" + this.state + ")");
            }

            //Check on of the Blocked machine to Iddle
            this.state = MachineStates.IDDLE;
            this.currentOperation = null;
            this.sIddleTime = startTime;

            return timeBlocked;
        }

        /// <summary>
        /// Called when a job finishes but another cannot begin at the machine
        /// because the transporter must remove the first job
        /// </summary>
        /// <param name="startTime">Time the first job finished</param>
        public void SetBlocked(Time startTime)
        {
                //This should not happen we should be coming from a WORKING STATE
            if (this.state == MachineStates.IDDLE)
            {
                  throw new Exception("Can not go to BLOCKED from current state (" + this.state + ")");
            }

            //Set the machine to blocked
            this.sBlockedTime = startTime;
            this.state = MachineStates.BLOCKED;
            
        }

        /// <summary>
        /// Called when a job arrives or the transporter removes a job that is blocking another
        /// </summary>
        /// <param name="startTime">Time the machine started working</param>
        /// <param name="operation">Operation it is working on</param>
        /// <returns>The time the machine was Iddle</returns>
        public Time SetWorking(Time startTime,Operation operation)
        {
            //End the previosu state
            Time timeIddle = startTime - sIddleTime;
            if (this.state == MachineStates.IDDLE)
            { 
                this.iddleTime += timeIddle;
            }
            else 
            {
                throw new Exception("Can not go to WORKING from current state (" + this.state + ")");
            }
            //keep track of the operation being done in that machine
            this.currentOperation = operation;

            //Set the operating time
            this.operatingTime += operation.ServiceTime;

            //Set the state to working
            this.state = MachineStates.WORKING;

            return timeIddle;
        }



    }

    /// <summary>
    /// States of the machine
    /// </summary>
    public enum MachineStates 
    { 
        /// <summary>
        /// 
        /// </summary>
        WORKING,
        /// <summary>
        /// 
        /// </summary>
        IDDLE,
        /// <summary>
        /// 
        /// </summary>
        BLOCKED 
    }
}
